﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Linq;

using iTool.Cloud.DataSearch.ServiceProvider;
using iTool.Common;

using Lucene.Net.Store;

using Orleans;

namespace iTool.Cloud.DataSearch.DirectoryProvider
{
    public class iToolCloudDirectory : Directory
    {
        readonly IClusterClient iCluster;
        readonly ILuceneDirectoryService iLuceneDirectoryService;

        protected internal LockFactory? interalLockFactory;
        public override LockFactory LockFactory => interalLockFactory ?? new iToolCloudLockFactory(tableNameHash, this.isLocalService);

        private readonly long tableNameHash;
        private readonly bool isLocalService;


        public iToolCloudDirectory(string tableName, bool isLocalService)
        {
            this.isLocalService = isLocalService;
            this.tableNameHash = JenkinsHash.ComputeHash(tableName);
            this.SetLockFactory(new iToolCloudLockFactory(tableNameHash, this.isLocalService));
            this.iCluster = iBox.GetService<IClusterClient>("IClusterService");
            this.iLuceneDirectoryService =
                this.isLocalService ? IDirectoryServiceFactory<LuceneDirectoryService>.GetService(tableNameHash, String.Empty) :
                this.iCluster.GetGrain<ILuceneDirectoryService>(tableNameHash);
        }

        // 删除文件
        public override void DeleteFile(string name)
        {
            this.iLuceneDirectoryService.DeleteFileAsync(name).Wait();
        }

        // 判断是否存在
        [Obsolete]
        public override bool FileExists(string name)
        {
            return this.iLuceneDirectoryService.FileExistsAsync(name).Result;
        }

        // 读取指定数据长度
        public override long FileLength(string name)
        {
            var service =
                this.isLocalService ? IDirectoryServiceFactory<IndexFieldManageService>.GetService(tableNameHash, name) :
                this.iCluster.GetGrain<IIndexFieldManageService>(tableNameHash, name);
            return  service.LengthAsync().Result;
        }

        /// <summary>
        /// 返回一个字符串数组，目录中每个文件一个字符串。
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public override string[] ListAll()
        {
            return this.iLuceneDirectoryService.ListAllAsync().Result;
        }


        /// <summary>
        /// 理论应该写入文件
        /// 确保对该文件的任何写入都移动到稳定的存储。Lucene使用它来正确地提交对索引的更改，以防止机器/操作系统崩溃损坏索引。
        /// </summary>
        /// <param name="names"></param>
        /// <exception cref="NotImplementedException"></exception>
        public override void Sync(ICollection<string> names)
        {
            Console.WriteLine("Sync:"+DateTime.Now+ "---"+String.Join(',',names));
            Task.WaitAll(names.Select(field => (
                this.isLocalService ? 
                    IDirectoryServiceFactory<IndexFieldManageService>.GetService(tableNameHash, field).FlushAsync() :
                    this.iCluster.GetGrain<IIndexFieldManageService>(tableNameHash, field).FlushAsync()
            )).ToArray());
        }

        #region Input/Output

        // 读取数据
        public override IndexInput OpenInput(string name, IOContext context) => new iToolCloudIndexInput(this.tableNameHash, name, context, this.isLocalService);


        // 写入数据
        public override IndexOutput CreateOutput(string name, IOContext context)
        {
            var estimatedSegmentSize = (int?)(context.FlushInfo?.EstimatedSegmentSize > 0
                    ? 
                    context.FlushInfo?.EstimatedSegmentSize //  / context.FlushInfo?.NumDocs * 300
                    : 
                    (context.MergeInfo?.EstimatedMergeBytes > 0 
                    ? context.MergeInfo?.EstimatedMergeBytes //  / context.MergeInfo?.TotalDocCount * 300
                    : null));

            return new iToolCloudIndexOutput(this.tableNameHash, name, context, estimatedSegmentSize, this.isLocalService);
        }

        #endregion

        #region lock
        /// <summary>
        /// 设置锁工程
        /// </summary>
        public override void SetLockFactory(LockFactory lockFactory)
        {
            this.interalLockFactory = lockFactory;
        }

        /// <summary>
        /// 清除锁
        /// </summary>
        /// <param name="name"></param>
        public override void ClearLock(string name) => this.LockFactory.ClearLock(name);

        /// <summary>
        /// 创建锁
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public override Lock MakeLock(string name) => this.LockFactory.MakeLock(name);

        #endregion

        /// <summary>
        /// 释放实例
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if(this.isLocalService) IDirectoryServiceFactory<LuceneDirectoryService>.Dispose(tableNameHash, String.Empty);
        }
    }
}
